#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/time.h>
#include <linux/uinput.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>

static pthread_t threadIds[10];
static char devicesUsed[10];
static char *devicesList[10] = {
    "/dev/input/event0",
    "/dev/input/event1",
    "/dev/input/event2",
    "/dev/input/event3",
    "/dev/input/event4",
    "/dev/input/event5",
    "/dev/input/event6",
    "/dev/input/event7",
    "/dev/input/event8",
    "/dev/input/event9",
};

typedef struct{
    int *mouse_fd;
    char *input;
    char* enable;
}THREAD_ARGS;

long timestamp()
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (tv.tv_sec*1000 + tv.tv_usec/1000);
}

void mouse_report_key(int fd, uint16_t type, uint16_t keycode, int32_t value)
{
	struct input_event ev;
 
	memset(&ev, 0, sizeof(struct input_event));
 
	ev.type = type;
	ev.code = keycode;
	ev.value = value;
 
	if (write(fd, &ev, sizeof(struct input_event)) < 0) {
		printf("key report error\n");
	}
}

int create_input_dev(void)
{
	struct uinput_user_dev mouse;
	int fd, ret;
 
	fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
	if (fd < 0) {
		return fd;
	}
 
	ioctl(fd, UI_SET_EVBIT, EV_SYN);
 
	ioctl(fd, UI_SET_EVBIT, EV_KEY);
	ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
	ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
	ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
 
	ioctl(fd, UI_SET_EVBIT, EV_REL);
	ioctl(fd, UI_SET_RELBIT, REL_X);
	ioctl(fd, UI_SET_RELBIT, REL_Y);
 
	/*ioctl(fd, UI_SET_EVBIT, EV_ABS);
	ioctl(fd, UI_SET_ABSBIT, ABS_X);
	ioctl(fd, UI_SET_ABSBIT, ABS_Y);
	ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE);*/
 
	memset(&mouse, 0, sizeof(struct uinput_user_dev));
	snprintf(mouse.name, UINPUT_MAX_NAME_SIZE, "mouse");
	mouse.id.bustype = BUS_USB;
	mouse.id.vendor = 0x1234;
	mouse.id.product = 0xfedc;
	mouse.id.version = 1;
 
	/*mouse.absmin[ABS_X] = 0;
	mouse.absmax[ABS_X] = 1023;
	mouse.absfuzz[ABS_X] = 0;
	mouse.absflat[ABS_X] = 0;
	mouse.absmin[ABS_Y] = 0;
	mouse.absmax[ABS_Y] = 767;
	mouse.absfuzz[ABS_Y] = 0;
	mouse.absflat[ABS_Y] = 0;*/
 
	ret = write(fd, &mouse, sizeof(struct uinput_user_dev));
 
	ret = ioctl(fd, UI_DEV_CREATE);
	if (ret < 0) {
		close(fd);
		return ret;
	}
	sleep(1);
	return fd;
}

void close_dev(int fd)
{
	ioctl(fd, UI_DEV_DESTROY);
	close(fd);
}

void mouse_button_right(int fd)
{
	mouse_report_key(fd, EV_KEY, BTN_RIGHT, 1);
	mouse_report_key(fd, EV_SYN, SYN_REPORT, 0);
	mouse_report_key(fd, EV_KEY, BTN_RIGHT, 0);
	mouse_report_key(fd, EV_SYN, SYN_REPORT, 0);
}

//char *="/dev/input/event0";
static void* touch_to_right(void * inargs)
{
    THREAD_ARGS * args = (THREAD_ARGS *)inargs;
    int fd = -1;    
    struct input_event ev;
    int down_time = 0;
    int touch_down = 0;
    int touch_down_x = 0, touch_down_y = 0;
    int touch_last_x = 0, touch_last_y = 0;

    // 循环读取
    while(1) 
    {
        if( fd < 0)
        {
            // 打开设备
            fd = open(args->input, O_RDWR);
            if( fd < 0 )
            {
                printf("touch pad disconnect.\n");
                *args->enable = 0;
                break;
            }
            printf("touch pad connect.\n");
        }
        else
        {
            // 读取数据
            long t = timestamp();
            int rst = read(fd, &ev, sizeof(struct input_event));
            if( rst < 0)
            {
                printf("touch pad disconnect.\n");
                close(fd);
                fd = -1;
                *args->enable = 0;
                break;
            }
            else
            {
                // 打印当前触发类型
                printf("EV:%02X, CODE:%02X, VALUE:%d\n", ev.type, ev.code, ev.value);
                // if(touch_down == 1)
                // {
                //     int tc = timestamp() - down_time;
                //     if(tc > 500)
                //     {
                //         if(((touch_last_x - 10) < touch_down_x < (touch_last_x + 10)) && ((touch_last_y - 10) < touch_down_y < (touch_last_y + 10)))
                //         {
                //             printf("send right press.\n");
                //             mouse_button_right(*args->mouse_fd);
                //         }
                //         touch_down = 0;
                //     }
                // }
                if((ev.type == EV_MSC) || (ev.type == EV_SYN))
                {
                    continue;
                }

                if(ev.type == EV_KEY)
                {
                    if(ev.code == BTN_TOUCH)
                    {
                        if(ev.value == 0)
                        {
                            if(touch_down == 1)
                            {
                                int tc = timestamp() - down_time;
                                if(tc > 500)
                                {
                                    if(((touch_last_x - 10) < touch_down_x < (touch_last_x + 10)) && ((touch_last_y - 10) < touch_down_y < (touch_last_y + 10)))
                                    {
                                        printf("send right press.\n");
                                        mouse_button_right(*args->mouse_fd);
                                    }
                                    touch_down = 0;
                                }
                            }
                        }
                        else
                        {
                            touch_down = 1;
                            //触屏按下
                            down_time = timestamp();
                        }
                    }
                }
                if(ev.type == EV_ABS)
                {
                    if(ev.code == ABS_MT_POSITION_X)
                    {
                        if(touch_down == 0)
                        {
                            touch_down_x = ev.value;
                        }
                        touch_last_x = ev.value;
                    }
                    else if(ev.code == ABS_MT_POSITION_Y)
                    {
                        if(touch_down == 0)
                        {
                            touch_down_y = ev.value;
                        }
                        touch_last_y = ev.value;
                    }
                }
            }
        }
    }
    close(fd);
    printf("touch pad exit.\n");
    *args->enable = 0;
    // pthread_exit(NULL);
}

int readline(int fd, char *buf, int max)
{
    for(int i=0; i < max; i++)
    {
        char b = 0;
        int rst = read(fd, (char *)(buf + i), 1);
        if((buf[i] == (char)'\n') || (buf[i] == (char)'\0'))
        {
            return i + 1;
        }
    }
}

int getTouchId(char *buf)
{
    printf("查找 %s\n", buf);
    int input_did = open("/var/touch_infos", O_RDWR);
    if(input_did >= 0)
    {
        char * validName = (char *)malloc(1024);
        int i = 0;
        do
        {
            memset(validName, 0, 1024);
            int rlen = readline(input_did, validName, 1024);
            if(rlen > 1)
            {
                validName[rlen - 1] = 0;
                printf("Read len:%d", rlen);
                printf("No.: %d, cur: %s, check: %s. reslut:", i, buf, validName);
                // sleep(1);
                if(strstr(buf, validName) == NULL)
                {
                    printf("false.\n");
                    i ++;
                    continue;
                }
                printf("true.\n");
                free(validName);
                close(input_did);
                return i;
            }
        }while(validName[0] != '\0');
        free(validName);
        close(input_did);
        printf("没有找到和\"%s\"匹配的设置项。\n", buf);
        return -1;
    }
    else
    {
        printf("/var/touch_infos, 没有这个文件。\n");
        return -1;
    }
}

void checkTouchDevice(int *mouse_fd)
{
    printf("查找 开始\n");
    int did = open("/proc/bus/input/devices", O_RDWR);
    printf("打开input 结果 %d\n", did);
    if(did >= 0)
    {
        char * buf = (char *)malloc(1024);
        do
        {
            memset(buf, 0, 1024);
            int rlen = readline(did, buf, 1024);
            if(strstr(buf, "N: Name") == NULL)
                continue;
            buf[rlen-1] = 0;
            printf("查找 %s 是不是\n", buf);
            int touchId = getTouchId(buf);
            if(touchId < 0)
                continue;

            for(int i=0;i<6;i++)
            {
                memset(buf, 0, 1024);
                readline(did, buf, 1024);
                if(strstr(buf, "Handlers") == NULL)
                    continue;
                char *p = strtok(buf, "=");
                p = strtok(NULL, "=");
                printf("%s\n", p);
                for(int z=0;z<6;z++)
                {
                    char *p1 = strtok((z == 0 ? p : NULL), " ");
                    if(p1 == NULL)
                        break;
                    char *ev = (char *)malloc(strlen(p1));
                    memcpy(ev, p1, strlen(p1));
                    if(strstr(ev, "event") != NULL)
                    {
                        printf("fined touch at1: %s\n", ev);
                        if(strlen(ev) != 6)
                            continue;
                        int id = atoi(&ev[5]);
                        printf("fined touch at2: %d\n", id);
                        if(id > 9)
                            continue;
                        printf("fined touch at3: %d\n", devicesUsed[id]);
                        if(devicesUsed[id] > 0)
                            continue;
                        devicesUsed[id] = 1;
                        printf("fined touch at: %s %d\n", ev, id);
                        THREAD_ARGS args;
                        args.mouse_fd = mouse_fd;
                        args.input = devicesList[id];
                        args.enable = &devicesUsed[id];
                        touch_to_right(&args);
                        free(ev);
                        free(buf);
                        close(did);
                        return;
                    }
                    free(ev);
                }
            }
        }while(buf[0] != '\0');
        
        free(buf);
        close(did);
    }
}

int main(int argc, char **argv)
{
    int mouse_fd = create_input_dev();
    while(1)
    {
        checkTouchDevice(&mouse_fd);
        sleep(1);
    }
    close_dev(mouse_fd);
    return 0;
}